﻿using System.Collections.Generic;
using System.Linq;
using NeuralStock.DomainService.Interfaces;
using NeuralStock.DataAccess;
using NeuralStock.Common;
using NeuralStock.Entities;
using System;

namespace NeuralStock.DomainService.Implementation
{
    public class FinancialReportService : BaseService, IFinancialReportService
    {
        private readonly ICompanyQuotationService companyQuotationService;

        public FinancialReportService(ICompanyQuotationService companyQuotationService)
        {
            this.companyQuotationService = companyQuotationService;
        }

        public IEnumerable<FinancialReport> GetAll()
        {
            return DbContext.FinancialReport.Include("Company")
                .OrderBy(x => x.Company.Name)
                .ThenBy(x => x.Year)
                .ToList();
        }

        public IEnumerable<FinancialReport> GetAllForCompany(int companyId)
        {
            return DbContext.FinancialReport
                .Where(x => x.CompanyId == companyId);
        }

        public IEnumerable<FinancialReport> GetAllByCompanyAndYearSpan(int companyId, int startYear, int endYear)
        {
            return DbContext.FinancialReport
                .Where(x => x.CompanyId == companyId
                && x.Year >= startYear
                && x.Year <= endYear);
        }

        public IEnumerable<FinancialReport> GetFinancialReportsForCapEbit(int companyId, int lastReportYear, int analyzedReportsYearSpan)
        {
            var financialReports = GetAllForCompany(companyId);

            var firstQuotationDate = companyQuotationService.GetFirstQuotationDate(companyId);

            financialReports = financialReports
                .Where(x => x.Year >= firstQuotationDate.Year - 1)
                .Where(x => x.Year <= lastReportYear)
                .Where(x => x.Year >= lastReportYear - analyzedReportsYearSpan)
                .OrderByDescending(x => x.Year);

            return financialReports;
        }

        public FinancialReport Get(int companyId, int year)
        {
            return DbContext.FinancialReport
                .FirstOrDefault(x => x.CompanyId == companyId
                && x.Year == year);
        }

        public FinancialReport Get(int reportId)
        {
            return DbContext.FinancialReport
                .FirstOrDefault(x => x.Id == reportId);
        }

        public bool FinancialReportsExist(int companyId, int yearFrom, int yearTo)
        {
            var reports = DbContext.FinancialReport
                .Where(x => x.CompanyId == companyId
                    && x.Year >= yearFrom && x.Year <= yearTo).ToList();
            return reports.Count == (yearTo - yearFrom + 1);
        }

        public void Create(FinancialReportData financialReportData)
        {
            if (financialReportData.IsValid())
            {
                FinancialReport report = new FinancialReport()
                {
                    CompanyId = financialReportData.CompanyId.Value,
                    Year = financialReportData.Year.Value,
                    ProfitFromOperatingActivities = financialReportData.ProfitFromOperatingActivities,
                    NetProfit = financialReportData.NetProfit,
                    NetCashFlowsFromFinancialActivities = financialReportData.NetCashFlowsFromFinancialActivities,
                    NetCashFlowsFromInvestmentActivities = financialReportData.NetCashFlowsFromInvestmentActivities,
                    NetCashFlowsFromOperatingActivities = financialReportData.NetCashFlowsFromOperatingActivities,
                    ShortTermLiabilities = financialReportData.ShortTermLiabilities,
                    NumberOfShares = financialReportData.NumberOfShares,
                    Assets = financialReportData.Assets,
                    EquityCapital = financialReportData.EquityCapital,
                    LiabilitiesAndProvisionsForLiabilities = financialReportData.LiabilitiesAndProvisionsForLiabilities,
                    LongTermLiabilities = financialReportData.LongTermLiabilities,
                    NetRevenuesFromSalesOfGoodsAndMaterials = financialReportData.NetRevenuesFromSalesOfGoodsAndMaterials
                };
                DbContext.FinancialReport.AddObject(report);
                DbContext.SaveChanges();
            }
            else
            {
                // poki co nie dodajemy wadliwych raportow
                //throw new InvalidOperationException(string.Format("Invalid FinancialReport for {0} {1}", financialReportData.CompanyName, financialReportData.Year));
            }
        }

        public void Update(int reportId, FinancialReportData financialReportData)
        {
            if (financialReportData.IsValid())
            {
                FinancialReport report = Get(reportId);

                report.ProfitFromOperatingActivities = SetNullabledecimal(financialReportData.CompanyName, GetPropertyName(() => report.ProfitFromOperatingActivities), report.ProfitFromOperatingActivities, financialReportData.ProfitFromOperatingActivities);
                report.NetProfit = SetNullabledecimal(financialReportData.CompanyName, GetPropertyName(() => report.NetProfit), report.NetProfit, financialReportData.NetProfit);
                report.NetCashFlowsFromFinancialActivities = SetNullabledecimal(financialReportData.CompanyName, GetPropertyName(() => report.NetCashFlowsFromFinancialActivities), report.NetCashFlowsFromFinancialActivities, financialReportData.NetCashFlowsFromFinancialActivities);
                report.NetCashFlowsFromInvestmentActivities = SetNullabledecimal(financialReportData.CompanyName, GetPropertyName(() => report.NetCashFlowsFromInvestmentActivities), report.NetCashFlowsFromInvestmentActivities, financialReportData.NetCashFlowsFromInvestmentActivities);
                report.NetCashFlowsFromOperatingActivities = SetNullabledecimal(financialReportData.CompanyName, GetPropertyName(() => report.NetCashFlowsFromOperatingActivities), report.NetCashFlowsFromOperatingActivities, financialReportData.NetCashFlowsFromOperatingActivities);
                report.ShortTermLiabilities = SetNullabledecimal(financialReportData.CompanyName, GetPropertyName(() => report.ShortTermLiabilities), report.ShortTermLiabilities, financialReportData.ShortTermLiabilities);
                report.NumberOfShares = SetNullabledecimal(financialReportData.CompanyName, GetPropertyName(() => report.NumberOfShares), report.NumberOfShares, financialReportData.NumberOfShares);
                report.LiabilitiesAndProvisionsForLiabilities = SetNullabledecimal(financialReportData.CompanyName, GetPropertyName(() => report.LiabilitiesAndProvisionsForLiabilities), report.LiabilitiesAndProvisionsForLiabilities, financialReportData.LiabilitiesAndProvisionsForLiabilities);
                report.LongTermLiabilities = SetNullabledecimal(financialReportData.CompanyName, GetPropertyName(() => report.LongTermLiabilities), report.LongTermLiabilities, financialReportData.LongTermLiabilities);
                report.Assets = SetNullabledecimal(financialReportData.CompanyName, GetPropertyName(() => report.Assets), report.Assets, financialReportData.Assets);
                report.EquityCapital = SetNullabledecimal(financialReportData.CompanyName, GetPropertyName(() => report.EquityCapital), report.EquityCapital, financialReportData.EquityCapital);
                report.NetRevenuesFromSalesOfGoodsAndMaterials = SetNullabledecimal(financialReportData.CompanyName, GetPropertyName(() => report.NetRevenuesFromSalesOfGoodsAndMaterials), report.NetRevenuesFromSalesOfGoodsAndMaterials, financialReportData.NetRevenuesFromSalesOfGoodsAndMaterials);


                DbContext.SaveChanges();
            }
            else
            {
                throw new InvalidOperationException(string.Format("Invalid FinancialReport for {0} {1}", financialReportData.CompanyName, financialReportData.Year));
            }
        }

        public void Delete(int reportId)
        {
            FinancialReport report = Get(reportId);

            DbContext.FinancialReport.DeleteObject(report);
            DbContext.SaveChanges();
        }
    }
}
